﻿using System;
using System.Drawing;
using System.Drawing.Imaging;

namespace WindowsTest
{
    /// <summary>
    /// 图像增强类
    /// </summary>
    public class ImageEnhancing
    {
        /// <summary>
        /// 计算灰度映射表
        /// </summary>
        public static int[] PixelsMap(int x1, int y1, int x2, int y2)
        {
            var pMap = new int[256];

            if (x1 > 0)
            {
                double k1 = (double)y1 / x1;

                //按第1段斜率k1线性变换
                for (int i = 0; i < x1; i++)
                {
                    pMap[i] = (int)(k1 * i);
                }
            }

            double k2 = (double)(y2 - y1) / (x2 - x1);

            //按第2段斜率k2线性变换
            for (int i = x1 + 1; i <= x2; i++)
            {
                if (x2 != x1)
                {
                    pMap[i] = y1 + (int)(k2 * (i - x1));
                }
                else
                {
                    pMap[i] = y1;
                }
            }

            if (x2 < 255)
            {
                double k3 = (double)(255 - y2) / (255 - x2);

                //按第3段斜率k3线性变换
                for (int i = x2 + 1; i < 256; i++)
                {
                    pMap[i] = y2 + (int)(k3 * (i - x2));
                }
            }

            return pMap;
        }

        /// <summary>
        /// 对比度扩展
        /// </summary>
        /// <param name="bm">输入的影像</param>
        /// <param name="map">灰度映射表</param>
        /// <returns>对比度扩展后的影像</returns>
        public static Bitmap Stretch(Bitmap bm, int[] map)
        {
            var w = bm.Width;
            var h = bm.Height;
            var data = bm.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            unsafe
            {
                var ptr = (byte*)data.Scan0.ToPointer();
                for (int j = 0; j < h; j++)
                {
                    for (int i = 0; i < w; i++)
                    {
                        int r = ptr[2];
                        int g = ptr[1];
                        int b = ptr[0];

                        r = map[r];
                        g = map[g];
                        b = map[b];

                        if (r >= 255) r = 255;
                        if (r < 0) r = 0;
                        if (g >= 255) g = 255;
                        if (g < 0) g = 0;
                        if (b >= 255) b = 255;
                        if (b < 0) b = 0;

                        ptr[2] = (byte)r;
                        ptr[1] = (byte)g;
                        ptr[0] = (byte)b;

                        ptr += 3;
                    }
                    ptr += data.Stride - w * 3;
                }
            }

            bm.UnlockBits(data);
            return bm;
        }

        /// <summary>
        /// 直方图均衡化
        /// </summary>
        /// <param name="bm">输入的影像</param>
        /// <param name="hist">直方图</param>
        /// <returns>均衡化后的影像</returns>
        public static Bitmap HistQual(Bitmap bm, int[] hist)
        {
            var w = bm.Width;
            var h = bm.Height;
            double p = (double)255 / (w * h);
            var sum = new double[256];
            var outg = new int[256];

            sum[0] = hist[0];
            for (int i = 1; i < 256; i++)
            {
                sum[i] = sum[i - 1] + hist[i];
            }

            //灰度变换：i-->outg[i]
            for (int i = 0; i < 256; i++)
            {
                outg[i] = (int)(p * sum[i]);
            }

            var data = bm.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            unsafe
            {
                var ptr = (byte*)data.Scan0.ToPointer();
                for (int j = 0; j < h; j++)
                {
                    for (int i = 0; i < w; i++)
                    {
                        int g = ptr[2];

                        ptr[0] = ptr[1] = ptr[2] = (byte)outg[g];

                        ptr += 3;
                    }
                    ptr += data.Stride - w * 3;
                }
            }

            bm.UnlockBits(data);

            return bm;
        }

        /// <summary>
        /// 3X3阈值滤波
        /// </summary>
        /// <param name="bm">输入的影像</param>
        /// <returns>滤波处理后的影像</returns>
        public static Bitmap Threshold(Bitmap bm)
        {
            var w = bm.Width;
            var h = bm.Height;
            var data = bm.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            unsafe
            {
                var ptr = (byte*)data.Scan0.ToPointer();
                for (int j = 1; j < h - 1; j++)
                {
                    for (int i = 1; i < w - 1; i++)
                    {
                        int num = 0;     //计数器
                        const int _nT = 4; //计数器阈值
                        const int _t = 50; //阈值

                        //取3X3块的9个像素，求和
                        int sum = 0;//灰度和
                        for (int k = -1; k <= 1; k++)
                        {
                            for (int l = -1; l <= 1; l++)
                            {
                                if ((k != 0) || (l != 0))
                                {
                                    var ckl = ptr + (j + k) * data.Stride + (i + l) * 3;
                                    var cij = ptr + j * data.Stride + i * 3;
                                    int pkl = ckl[2];        //(i+k,j+l)处灰度值
                                    int pij = cij[2];        //(i,j)处灰度值
                                    int err = Math.Abs(pkl - pij);        //误差
                                    sum += pkl;
                                    if (err > _t)
                                    {
                                        num++;
                                    }
                                }
                            }
                        }
                        var avr = (byte)(sum / 8.0f);//灰度平均
                        if (num > _nT)
                        {
                            var p = ptr + j * data.Stride + i * 3;
                            p[0] = p[1] = p[2] = avr;
                        }
                    }
                }
            }

            bm.UnlockBits(data);
            return bm;
        }

        /// <summary>
        /// 3X3平均值滤波
        /// </summary>
        /// <param name="bm">输入的影像</param>
        /// <returns>平均值滤波处理后的影像</returns>
        public static Bitmap Average(Bitmap bm)
        {
            var w = bm.Width;
            var h = bm.Height;
            var data = bm.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            unsafe
            {
                var ptr = (byte*)data.Scan0.ToPointer();
                for (int j = 1; j < h - 1; j++)
                {
                    for (int i = 1; i < w - 1; i++)
                    {
                        //取3X3块的9个像素，求和
                        var sum = 0;
                        for (int k = -1; k <= 1; k++)
                        {
                            for (int l = -1; l <= 1; l++)
                            {
                                var r = (ptr + (j + k) * data.Stride + (i + l) * 3)[2];
                                sum += r;
                            }
                        }

                        var avr = (byte)(sum / 9.0f);//平均值
                        var p = ptr + j * data.Stride + i * 3;
                        p[0] = p[1] = p[2] = avr;
                    }
                }
            }
            bm.UnlockBits(data);
            return bm;
        }

        /// <summary>
        /// 中值滤波
        /// </summary>
        /// <param name="bm">输入的影像</param>
        /// <param name="n">中值滤波模板类型</param>
        /// <returns>滤波处理后的影像</returns>
        public static Bitmap Median(Bitmap bm, int n)
        {
            var w = bm.Width;
            var h = bm.Height;
            var data = bm.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            unsafe
            {
                var ptr = (byte*)data.Scan0.ToPointer();
                for (int j = 2; j < h - 2; j++)
                {
                    for (int i = 2; i < w - 2; i++)
                    {
                        var p = ptr + j * data.Stride + i * 3;
                        int m = 0, r = 0;
                        int[] dt;
                        if (n == 3)
                        {
                            dt = new int[25];

                            //取5X5块的25个像素
                            for (int k = -2; k <= 2; k++)
                            {
                                for (int l = -2; l <= 2; l++)
                                {
                                    //取（i+k,j+l)处的像素，赋于数组dt
                                    dt[m] = (ptr + (j + k) * data.Stride + (i + l) * 3)[2];
                                    m++;
                                }
                            }
                            //冒泡排序，输出中值
                            r = medianSorter(dt, 25);
                        }
                        else if (n == 1)
                        {
                            dt = new int[5];

                            //取1X5窗口5个像素
                            dt[0] = (p - 2 * data.Stride)[2];
                            dt[1] = (p - data.Stride)[2];
                            dt[2] = (p)[2];
                            dt[3] = (p + data.Stride)[2];
                            dt[4] = (p + 2 * data.Stride)[2];
                            r = medianSorter(dt, 5);//中值
                        }
                        else if (n == 2)
                        {
                            dt = new int[5];

                            //取1X5窗口5个像素
                            dt[0] = (p - (2 * 3))[2];
                            dt[1] = (p - (1 * 3))[2];
                            dt[2] = (p)[2];
                            dt[3] = (p + 1 * 3)[2];
                            dt[4] = (p + 2 * 3)[2];
                            r = medianSorter(dt, 5);//中值
                        }

                        p[0] = p[1] = p[2] = (byte)r;
                    }
                }
            }
            bm.UnlockBits(data);
            return bm;
        }

        /// <summary>
        /// 冒泡排序，输出中值
        /// </summary>
        /// <param name="dt">灰度值</param>
        /// <param name="m">像素个数</param>
        /// <returns>灰度中值</returns>
        private static int medianSorter(int[] dt, int m)
        {
            for (int k = m - 1; k >= 1; k--)
            {
                for (int l = 1; l <= k; l++)
                {
                    if (dt[l - 1] > dt[l])
                    {
                        int tem = dt[l];
                        dt[l] = dt[l - 1];
                        dt[l - 1] = tem;
                    }
                }
            }
            return dt[m / 2];
        }

        #region 低通滤波

        /// <summary>
        /// 3X3低通滤波方法
        /// </summary>
        /// <param name="bm">输入的影像</param>
        /// <param name="n">模板</param>
        /// <returns>低通滤波后的结果</returns>
        public static Bitmap LowPass(Bitmap bm, int n)
        {
            var w = bm.Width;
            var h = bm.Height;
            //定义扩展输入图像矩阵
            var exInpix = exinpix(bm, w, h);

            var data = bm.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            unsafe
            {
                var ptr = (byte*)data.Scan0.ToPointer();
                //低通滤波
                for (int j = 1; j < h + 1; j++)
                {
                    for (int i = 1; i < w + 1; i++)
                    {
                        var p = ptr + (j - 1) * data.Stride + (i - 1) * 3;
                        //低通模板
                        var ht = lowMatrix(n);
                        var sum = 0;
                        byte r = 0;
                        //求3X3窗口9个像素加权和
                        for (int k = -1; k < 2; k++)
                        {
                            for (int l = -1; l < 2; l++)
                            {
                                sum += ht[k + 1, l + 1] * exInpix[i + k, j + l];
                            }
                        }

                        if (n == 1)
                        {
                            r = (byte)(sum / 9);
                        }
                        else if (n == 2)
                        {
                            r = (byte)(sum / 10);
                        }
                        else if (n == 3)
                        {
                            r = (byte)(sum / 16);
                        }

                        p[0] = p[1] = p[2] = r;
                    }
                }
            }

            bm.UnlockBits(data);

            return bm;
        }

        /// <summary>
        /// 定义扩展输入图像矩阵
        /// </summary>
        /// <param name="bm">输入的影像</param>
        /// <param name="w">输入影像的宽</param>
        /// <param name="h">输入影像的高</param>
        /// <returns>扩展图像矩阵</returns>
        private static int[,] exinpix(Bitmap bm, int w, int h)
        {
            var exInpix = new int[w + 2, h + 2];
            var data = bm.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

            unsafe
            {
                var ptr = (byte*)data.Scan0.ToPointer();
                //获取非边界灰度值
                for (int j = 0; j < h; j++)
                {
                    for (int i = 0; i < w; i++)
                    {
                        exInpix[i + 1, j + 1] = (ptr + j * data.Stride + i * 3)[2];
                    }
                }
            }

            bm.UnlockBits(data);

            //四角点处理
            exInpix[0, 0] = exInpix[1, 1];
            exInpix[0, h + 1] = exInpix[1, h];
            exInpix[w + 1, 0] = exInpix[w, 1];
            exInpix[w + 1, h + 1] = exInpix[w, h];

            //上下边界处理
            for (int j = 1; j < h + 1; j++)
            {
                exInpix[0, j] = exInpix[1, j];//上边界
                exInpix[w + 1, j] = exInpix[w, j];//下边界
            }

            //左右边界处理
            for (int i = 1; i < w + 1; i++)
            {
                exInpix[i, 0] = exInpix[i, 1];//左边界
                exInpix[i, h + 1] = exInpix[i, h];//右边界
            }

            return exInpix;
        }

        /// <summary>
        /// 低通滤波模板
        /// </summary>
        /// <param name="n">模版类型</param>
        /// <returns>模版</returns>
        private static int[,] lowMatrix(int n)
        {
            var h = new int[3, 3];
            if (n == 1)//h1
            {
                h[0, 0] = 1; h[0, 1] = 1; h[0, 2] = 1;
                h[1, 0] = 1; h[1, 1] = 1; h[1, 2] = 1;
                h[2, 0] = 1; h[2, 1] = 1; h[2, 2] = 1;
            }
            else if (n == 2)//h2
            {
                h[0, 0] = 1; h[0, 1] = 1; h[0, 2] = 1;
                h[1, 0] = 1; h[1, 1] = 2; h[1, 2] = 1;
                h[2, 0] = 1; h[2, 1] = 1; h[2, 2] = 1;
            }
            else if (n == 3)//h3
            {
                h[0, 0] = 1; h[0, 1] = 2; h[0, 2] = 1;
                h[1, 0] = 2; h[1, 1] = 4; h[1, 2] = 2;
                h[2, 0] = 1; h[2, 1] = 2; h[2, 2] = 1;
            }
            return h;
        }

        #endregion

        #region 高通滤波

        /// <summary>
        /// 3X3高通滤波方法
        /// </summary>
        /// <param name="bm">输入的影像</param>
        /// <param name="n">高通滤波模板类型</param>
        /// <returns>高通滤波处理后的影像</returns>
        public static Bitmap HighPass(Bitmap bm, int n)
        {
            var w = bm.Width;
            var h = bm.Height;

            //定义扩展输入图像矩阵
            var exInpix = exinpix(bm, w, h);

            var data = bm.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            unsafe
            {
                var ptr = (byte*)data.Scan0.ToPointer();
                //高通滤波
                for (int j = 1; j < h + 1; j++)
                {
                    for (int i = 1; i < w + 1; i++)
                    {
                        int sum = 0;

                        //高通模板
                        int[,] hm = highMatrix(n);

                        //求3X3窗口9个像素加权和
                        for (int k = -1; k <= 1; k++)
                        {
                            for (int l = -1; l <= 1; l++)
                            {
                                sum += hm[k + 1, l + 1] * exInpix[i + k, j + l];
                            }
                        }

                        byte r;

                        if (n == 4) r = (byte)(sum / 7);
                        else if (n == 5) r = (byte)(sum / 2);
                        else r = (byte)sum;

                        if (r > 255) r = 255;

                        var p = ptr + (j - 1) * data.Stride + (i - 1) * 3;
                        p[0] = p[1] = p[2] = r;
                    }
                }
            }

            bm.UnlockBits(data);
            return bm;
        }

        /// <summary>
        /// 高能滤波模板
        /// </summary>
        /// <param name="n">模板类型</param>
        /// <returns>高能滤波模板</returns>
        private static int[,] highMatrix(int n)
        {
            var h = new int[3, 3];
            switch (n)
            {
                case 1://H1
                    h[0, 0] = 0; h[0, 1] = -1; h[0, 2] = 0;
                    h[1, 0] = -1; h[1, 1] = 5; h[1, 2] = -1;
                    h[2, 0] = 0; h[2, 1] = -1; h[2, 2] = 0;
                    break;
                case 2://H2
                    h[0, 0] = -1; h[0, 1] = -1; h[0, 2] = -1;
                    h[1, 0] = -1; h[1, 1] = 9; h[1, 2] = -1;
                    h[2, 0] = -1; h[2, 1] = -1; h[2, 2] = -1;
                    break;
                case 3://H3
                    h[0, 0] = 1; h[0, 1] = -2; h[0, 2] = 1;
                    h[1, 0] = -2; h[1, 1] = 5; h[1, 2] = -2;
                    h[2, 0] = 1; h[2, 1] = -2; h[2, 2] = 1;
                    break;
                case 4://H4
                    h[0, 0] = -1; h[0, 1] = -2; h[0, 2] = -1;
                    h[1, 0] = -2; h[1, 1] = 19; h[1, 2] = -2;
                    h[2, 0] = -1; h[2, 1] = -2; h[2, 2] = -1;
                    break;
                case 5://H5
                    h[0, 0] = -2; h[0, 1] = 1; h[0, 2] = -2;
                    h[1, 0] = 1; h[1, 1] = 6; h[1, 2] = 1;
                    h[2, 0] = -2; h[2, 1] = 1; h[2, 2] = -2;
                    break;
            }
            return h;
        }

        #endregion

        #region 图像几何变换

        /// <summary>
        /// 图像旋转
        /// </summary>
        /// <param name="bm">输入的影像</param>
        /// <param name="beta">旋转角度</param>
        /// <returns>旋转后的影像</returns>
        public static Bitmap ImRotate(Bitmap bm, float beta)
        {
            //1.计算旋转后的新图像最大最小包围盒宽高
            var w = bm.Width;
            var h = bm.Height;
            var owh = (int)(Math.Sqrt(w * w + h * h + 0.5));
            var obm = new Bitmap(owh, owh);
            double t = beta / 180;

            var cosBeta = (float)(Math.Cos(t * Math.PI));//顺时针旋转
            var sinBeta = (float)(Math.Sin(t * Math.PI));

            var data = bm.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            var dataObm = obm.LockBits(new Rectangle(0, 0, owh, owh), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            unsafe
            {
                var p = (byte*)data.Scan0.ToPointer();
                var ptr = (byte*)dataObm.Scan0.ToPointer();
                //2.逆旋转变换，计算输出图像点p(i,j)所对应的原图像的坐标(x,y)
                for (int j = 0; j < owh; j++)
                {
                    for (int i = 0; i < owh; i++)
                    {
                        //旋转变换的逆变换
                        float u = (i - owh / 2) * cosBeta + (j - owh / 2) * sinBeta;
                        float v = (j - owh / 2) * cosBeta - (i - owh / 2) * sinBeta;

                        //换成相对于原图像的绝对坐标
                        u += (float)w / 2;
                        v += (float)h / 2;

                        var x = (int)u;
                        var y = (int)v;

                        //3.检验条件，对满足条件的点(x,y)，赋值F(i,j)=f(x,y)
                        if ((x > 0) && (x < w) && (y > 0) && (y < h))
                        {
                            var _p = p + y * data.Stride + x * 3;
                            var _ptr = ptr + j * dataObm.Stride + i * 3;
                            _ptr[0] = _p[0];
                            _ptr[1] = _p[1];
                            _ptr[2] = _p[2];

                            //int r = (bm.GetPixel(x, y)).R;
                            //int g = (bm.GetPixel(x, y)).G;
                            //int b = (bm.GetPixel(x, y)).B;
                            //obm.SetPixel(i, j, Color.FromArgb(r, g, b));
                        }
                    }
                }
            }

            bm.UnlockBits(data);
            obm.UnlockBits(dataObm);
            return obm;
        }

        /// <summary>
        /// 最邻近插值
        /// </summary>
        /// <param name="bm">输入的影像</param>
        /// <param name="p">缩放率</param>
        /// <returns>缩放后的影像</returns>
        public static Bitmap NearNeighbor(Bitmap bm, double p)
        {
            var w = bm.Width;
            var h = bm.Height;
            var ow = (int)(p * w);
            var oh = (int)(p * h);
            var obm = new Bitmap(ow, oh);
            var data = bm.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            var dataObm = obm.LockBits(new Rectangle(0, 0, ow, oh), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            unsafe
            {
                var pt = (byte*)data.Scan0.ToPointer();
                var ptr = (byte*)dataObm.Scan0.ToPointer();
                for (int i = 0; i < ow; i++)
                {
                    var u = (int)(i / p);
                    for (int j = 0; j < oh; j++)
                    {
                        var v = (int)(j / p);
                        var _pt = pt + v * data.Stride + u * 3;
                        var _ptr = ptr + j * dataObm.Stride + i * 3;
                        _ptr[0] = _pt[0];
                        _ptr[1] = _pt[1];
                        _ptr[2] = _pt[2];
                    }
                }
            }

            bm.UnlockBits(data);
            obm.UnlockBits(dataObm);

            return obm;
        }

        /// <summary>
        /// 错切变换
        /// </summary>
        /// <param name="bm">输入的影像</param>
        /// <param name="sh">错切比例</param>
        /// <returns>错切变换后的影像</returns>
        public static Bitmap ShearTest(Bitmap bm, double sh)
        {
            var w = bm.Width;
            var h = bm.Height;
            //1.计算图像四角点坐标
            var x2 = (int)(w - 1 + (h - 1) * sh);
            var y2 = (int)((w - 1) * sh + h - 1);

            //2.计算包围图像的最小矩形，即包围盒的宽和高
            var ow = x2 + 1;
            var oh = y2 + 1;

            //3.包围盒内
            var obm = new Bitmap(ow, oh);
            var data = bm.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            var dataObm = obm.LockBits(new Rectangle(0, 0, ow, oh), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            unsafe
            {
                var p = (byte*)data.Scan0.ToPointer();
                var ptr = (byte*)dataObm.Scan0.ToPointer();

                //4.根据错切变换公式，计算(u,v)并赋值F(u,v)=f(i,j)
                for (int i = 0; i < w; i++)
                {
                    for (int j = 0; j < h; j++)
                    {
                        var u = (int)(j * sh + i);
                        var v = (int)(j + i * sh);

                        var _p = p + j * data.Stride + i * 3;
                        var _ptr = ptr + v * dataObm.Stride + u * 3;
                        _ptr[0] = _p[0];
                        _ptr[1] = _p[1];
                        _ptr[2] = _p[2];
                        //int r = (bm.GetPixel(i, j)).R;
                        //int g = (bm.GetPixel(i, j)).G;
                        //int b = (bm.GetPixel(i, j)).B;
                        //obm.SetPixel(u, v, Color.FromArgb(r, g, b));
                    }
                }
            }

            bm.UnlockBits(data);
            obm.UnlockBits(dataObm);
            return obm;
        }

        /// <summary>
        /// 平移变换
        /// </summary>
        /// <param name="bm">输入的影像</param>
        /// <param name="x">横向平移量</param>
        /// <param name="y">纵向平移量</param>
        /// <returns>平移变换后的影像</returns>
        public static Bitmap TranslateTest(Bitmap bm, int x, int y)
        {
            var w = bm.Width;
            var h = bm.Height;
            var ow = w + x;
            var oh = h + y;

            //包围盒内
            var obm = new Bitmap(ow, oh);
            var data = bm.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            var dataObm = obm.LockBits(new Rectangle(0, 0, ow, oh), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            unsafe
            {
                var p = (byte*)data.Scan0.ToPointer();
                var ptr = (byte*)dataObm.Scan0.ToPointer();
                for (int i = 0; i < w; i++)
                {
                    for (int j = 0; j < h; j++)
                    {
                        var u = i + x;
                        var v = j + y;

                        var _p = p + j * data.Stride + i * 3;
                        var _ptr = ptr + v * dataObm.Stride + u * 3;
                        _ptr[0] = _p[0];
                        _ptr[1] = _p[1];
                        _ptr[2] = _p[2];

                        //int r = (bm.GetPixel(i, j)).R;
                        //int g = (bm.GetPixel(i, j)).G;
                        //int b = (bm.GetPixel(i, j)).B;
                        //obm.SetPixel(u, v, Color.FromArgb(r, g, b));
                    }
                }
            }
            bm.UnlockBits(data);
            obm.UnlockBits(dataObm);

            return obm;
        }

        /// <summary>
        /// 双线性插值
        /// </summary>
        /// <param name="bm">输入的影像</param>
        /// <param name="p">缩放比例</param>
        /// <returns>双线性插值缩放后的影像</returns>
        public static Bitmap BiLinear(Bitmap bm, double p)
        {
            var w = bm.Width;
            var h = bm.Height;
            var ow = (int)(p * w);
            var oh = (int)(p * h);
            var obm = new Bitmap(ow, oh);
            var data = bm.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            var dataObm = obm.LockBits(new Rectangle(0, 0, ow, oh), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            unsafe
            {
                var ptr1 = (byte*)data.Scan0.ToPointer();
                var ptr2 = (byte*)dataObm.Scan0.ToPointer();
                for (int j = 0; j < oh - 1; j++)
                {
                    double dy = j / p;
                    var iy = (int)dy;
                    if (iy > h - 2) iy = h - 2;
                    double dY = dy - iy;

                    for (int i = 0; i < ow - 1; i++)
                    {
                        double dx = i / p;
                        var ix = (int)dx;
                        if (ix > w - 2) ix = w - 2;
                        double dX = dx - ix;
                        var ptr10 = ptr1 + iy * data.Stride + ix * 3;
                        var ptr11 = ptr1 + iy * data.Stride + (ix + 1) * 3;
                        var ptr12 = ptr1 + (iy + 1) * data.Stride + ix * 3;
                        var ptr13 = ptr1 + (iy + 1) * data.Stride + (ix + 1) * 3;

                        var r = (int)
                                ((1 - dX) * (1 - dY) * ptr10[2] + dX * (1 - dY) * ptr11[2] +
                                 (1 - dX) * dY * ptr12[2] + dX * dY * ptr13[2]);

                        var g = (int)
                                ((1 - dX) * (1 - dY) * ptr10[1] + dX * (1 - dY) * ptr11[1] +
                                 (1 - dX) * dY * ptr12[1] + dX * dY * ptr13[1]);

                        var b = (int)
                                ((1 - dX) * (1 - dY) * ptr10[0] + dX * (1 - dY) * ptr11[0] +
                                 (1 - dX) * dY * ptr12[0] + dX * dY * ptr13[0]);

                        if (r < 0) r = 0;
                        if (r > 255) r = 255;
                        if (g < 0) g = 0;
                        if (g > 255) g = 255;
                        if (b < 0) b = 0;
                        if (b > 255) b = 255;

                        var _ptr2 = ptr2 + j * dataObm.Stride + i * 3;
                        _ptr2[2] = (byte)r;
                        _ptr2[1] = (byte)g;
                        _ptr2[0] = (byte)b;
                    }
                }
            }
            bm.UnlockBits(data);
            obm.UnlockBits(dataObm);
            return obm;
        }

        /// <summary>
        /// 三次卷积算法
        /// </summary>
        /// <param name="bm">输入的影像</param>
        /// <param name="x">被缩放在区域在左上角的横坐标</param>
        /// <param name="y">被缩放在区域在左上角的纵坐标</param>
        /// <param name="scansize">原图像的扫描宽度</param>
        /// <param name="scalex">水平方向上的缩放比例</param>
        /// <param name="scaley">垂直方向上的缩放比例</param>
        /// <returns>缩放后的图像像素数据</returns>
        public static Bitmap Scale(Bitmap bm, int x, int y, int scansize, double scalex, double scaley)
        {
            var w = bm.Width;
            var h = bm.Height;
            var ow = (int)(w * scalex + 0.5f);
            var oh = (int)(h * scaley + 0.5f);

            var dst = new Bitmap(ow, oh);//目标影像

            //原图像的宽度
            int srcWidth = scansize;

            //原图像可以扫描的总行数，即原图像的高度
            int srcHeight = (w * h) / scansize;

            //width---height:处理区域的宽度和高度
            //如果参数传递是合法的，那么它们就是w,h
            int width = w;
            int height = h;

            if ((x + w) > scansize) width = scansize - x;
            if ((y + h) > srcHeight) height = srcHeight - y;

            var dstWidth = (int)(width * scalex + 0.5f);
            var dstHeight = (int)(height * scaley + 0.5f);

            var data = dst.LockBits(new Rectangle(0, 0, ow, oh), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            unsafe
            {
                var ptr = (byte*)data.Scan0.ToPointer();
                //进行反向变换
                //i----按行，j----按例
                for (int j = 0; j < dstHeight; j++)
                {
                    //按反向变换法，获取第i行所对应的原图像的位置::行::例
                    double yInverseMap = j / scaley;

                    var yLt = (int)yInverseMap;

                    //垂直方向偏移量
                    double v = yInverseMap - yLt;

                    //左上角的y坐标
                    yLt += y;

                    for (int i = 0; i < dstWidth; i++)
                    {
                        double xInverseMap = i / scalex;

                        var xLt = (int)xInverseMap;

                        //水平方向偏移量
                        double u = xInverseMap - xLt;

                        //左上角的y坐标
                        xLt += x;

                        //通过计算获取变换后的点
                        int dc = interpolate(bm, xLt, yLt, u, v, srcWidth, srcHeight);

                        int r = (dc >> 16) & 0xff;
                        int g = (dc >> 8) & 0xff;
                        int b = dc & 0xff;

                        var _ptr = ptr + j * data.Stride + i * 3;
                        _ptr[2] = (byte)r;
                        _ptr[1] = (byte)g;
                        _ptr[0] = (byte)b;
                        //dst.SetPixel(i, j, Color.FromArgb(r, g, b));
                    }
                }
            }
            dst.UnlockBits(data);
            return dst;
        }

        /// <summary>
        /// 通过计算获取变换后的点
        /// </summary>
        /// <param name="src">原图像</param>
        /// <param name="x">经过反向变换后，与反向变换点最接近的原图像的左上角点的横坐标</param>
        /// <param name="y">经过反向变换后，与反向变换点最接近的原图像的左上角点的纵坐标</param>
        /// <param name="u">反向变换点相对(x,y)点的横向偏移量</param>
        /// <param name="v">反向变换点相对(x,y)点的纵向偏移量</param>
        /// <param name="scanw">原图像的扫描宽度</param>
        /// <param name="scanh">原图像的扫描高度</param>
        /// <returns></returns>
        private static int interpolate(Bitmap src, int x, int y, double u, double v, int scanw, int scanh)
        {
            //邻近区域的像素值
            var red = new int[4, 4];
            var green = new int[4, 4];
            var blue = new int[4, 4];

            //邻近区域的坐标
            var xx = new int[4];
            var yy = new int[4];

            xx[0] = x - 1;
            xx[1] = x;
            xx[2] = x + 1;
            xx[3] = x + 2;

            yy[0] = y - 1;
            yy[1] = y;
            yy[2] = y + 1;
            yy[3] = y + 2;

            if (xx[0] < 0) xx[0] = 0;
            if (yy[0] < 0) yy[0] = 0;
            if (xx[2] > scanw - 1) xx[2] = scanw - 1;
            if (yy[2] > scanh - 1) yy[2] = scanh - 1;
            if (xx[3] > scanw - 1) xx[3] = scanw - 1;
            if (yy[3] > scanh - 1) yy[3] = scanh - 1;

            var data = src.LockBits(new Rectangle(xx[0], yy[0], scanw - xx[0] < 4 ? scanw - xx[0] : 4, scanh - yy[0] < 4 ? scanh - yy[0] : 4), ImageLockMode.ReadWrite,
                                    PixelFormat.Format24bppRgb);

            unsafe
            {
                var ptr = (byte*)data.Scan0.ToPointer();
                //获取4*4区域的像素值
                for (int i = 0; i < 4; i++)
                {
                    for (int j = 0; j < 4; j++)
                    {
                        var _ptr = ptr + j * 12 + i * 3;
                        red[i, j] = _ptr[2];
                        green[i, j] = _ptr[1];
                        blue[i, j] = _ptr[0];
                    }
                }
            }
            src.UnlockBits(data);

            var su = new double[4];
            var sv = new double[4];

            su[0] = sinx_x(1.0 + u);
            su[1] = sinx_x(u);
            su[2] = sinx_x(1.0 - u);
            su[3] = sinx_x(2.0 - u);

            sv[0] = sinx_x(1.0 + v);
            sv[1] = sinx_x(v);
            sv[2] = sinx_x(1.0 - v);
            sv[3] = sinx_x(2.0 - v);

            //作矩阵乘积：sv*red,sv*green,sv*blue
            var svR = new double[4];
            var svG = new double[4];
            var svB = new double[4];

            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    svR[i] += (sv[j] * red[j, i]);
                    svG[i] += (sv[j] * green[j, i]);
                    svB[i] += (sv[j] * blue[j, i]);
                }
            }

            var r = (int)(su[0] * svR[0] + su[1] * svR[1] + su[2] * svR[2] + su[3] * svR[3]);
            var g = (int)(su[0] * svG[0] + su[1] * svG[1] + su[2] * svG[2] + su[3] * svG[3]);
            var b = (int)(su[0] * svB[0] + su[1] * svB[1] + su[2] * svB[2] + su[3] * svB[3]);

            r = (r < 0) ? 0 : ((r > 255) ? 255 : r);
            g = (g < 0) ? 0 : ((g > 255) ? 255 : g);
            b = (b < 0) ? 0 : ((b > 255) ? 255 : b);

            return ((r << 16) | (g << 8) | b);
        }

        /// <summary>
        /// 计算sin(x)/x的值，采用多项式展开
        /// </summary>
        /// <param name="x">输入的值</param>
        /// <returns>返回sin(x)/x</returns>
        private static double sinx_x(double x)
        {
            double xAbs = Math.Abs(x);
            double xX = xAbs * xAbs;
            double xXx = xX * xAbs;

            if (xAbs < 1.0) return (1.0 - 2.0 * xX + xXx);
            if (xAbs < 2.0) return (4.0 - 8.0 * xAbs + 5.0 * xX - xXx);
            return 0.0;
        }

        #endregion
    }
}
